package com.zhkc.wisdom.auth;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.json.JSONUtil;
import com.zhkc.wisdom.auth.config.StpInterfaceImpl;
import com.zhkc.wisdom.auth.config.WhiteListProperties;
import com.zhkc.wisdom.auth.filter.ForwardAuthFilter;
import com.zhkc.wisdom.common.configure.constant.ConfigureConstant;
import com.zhkc.wisdom.common.pojo.enums.ResponseCodeEnum;
import com.zhkc.wisdom.common.pojo.vo.ResultVO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.MediaType;

import java.util.Objects;


@Slf4j
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnProperty(prefix = ConfigureConstant.ZHKC_PROPERTIES_PREFIX
        + ".auth", name = "enabled", havingValue = "true", matchIfMissing = false)
public class AuthConfiguration {

    @Resource
    private WhiteListProperties whiteListProperties;

    @Value("${zhkc.test.enabled:true}")
    private Boolean testEnabled;

    /**
     * 注册 [Sa-Token全局过滤器]
     */
    @Bean
    public SaReactorFilter getSaServletFilter() {
        return new SaReactorFilter()
                // 指定 拦截路由 与 放行路由
                .addInclude("/**").addExclude(whiteListProperties.getExcludes())
                // 认证函数: 每次请求执行
                .setAuth(obj -> {
                    if (testEnabled) {
                        log.info("---------- 进入Sa-Token全局认证 -----------");
                        // 登录认证
                        SaRouter
                                // 拦截的 path 列表，可以写多个 */
                                .match("/**")
                                // 排除掉的 path 列表，可以写多个
                                .notMatch(whiteListProperties.getExcludes())
                                // 要执行的校验动作，可以写完整的 lambda 表达式
                                .check(r -> StpUtil.checkLogin());
                    }
                })

                // 异常处理函数：每次认证函数发生异常时执行此函数
                .setError(e -> {
                    log.info("---------- 进入Sa-Token异常处理 -----------" + e.getMessage());
                    SaHolder.getResponse().setHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE);
                    if (e instanceof NotLoginException) {
                        //需要进行json字符串转换，不然前端转换会出错
                        return JSONUtil.toJsonStr(ResultVO.fail(getMsg(((NotLoginException) e).getCode())));
                    } else {
                        return JSONUtil.toJsonStr(ResultVO.fail(e.getMessage()));
                    }

                })

                // 前置函数：在每次认证函数之前执行（BeforeAuth 不受 includeList 与 excludeList 的限制，所有请求都会进入）
                .setBeforeAuth(r -> {
                    // ---------- 设置一些安全响应头 ----------
                    SaHolder.getResponse()
                            // 服务器名称
                            .setServer("sa-server")
                            // 是否可以在iframe显示视图： DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
                            .setHeader("X-Frame-Options", "SAMEORIGIN")
                            // 是否启用浏览器默认XSS防护： 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时，停止渲染页面
                            .setHeader("X-XSS-Protection", "1; mode=block")
                            // 禁用浏览器内容嗅探
                            .setHeader("X-Content-Type-Options", "nosniff")
                    ;
                })
                ;
    }

    private ResponseCodeEnum getMsg(Integer code) {
        if (Objects.equals(code, ResponseCodeEnum.BE_OVERDUE_ERROR.getCode())) {
            return ResponseCodeEnum.BE_OVERDUE_ERROR;
        } else if (Objects.equals(code, ResponseCodeEnum.TOKEN_NULL_ERROR.getCode())) {
            return ResponseCodeEnum.TOKEN_NULL_ERROR;
        } else if (Objects.equals(code, ResponseCodeEnum.INVALID_ERROR.getCode())) {
            return ResponseCodeEnum.INVALID_ERROR;
        } else {
            return ResponseCodeEnum.SYSTEM_ERROR;
        }
    }

    @Bean
    @ConditionalOnProperty(prefix = ConfigureConstant.ZHKC_PROPERTIES_PREFIX
            + ".permission", name = "enabled", havingValue = "true", matchIfMissing = false)
    public ForwardAuthFilter forwardAuthFilter() {
        return new ForwardAuthFilter();
    }

    /**
     * Sa-Token 自定义权限加载接口实现类
     *
     * @return
     */
    @Bean
    public StpInterfaceImpl stpInterface() {
        return new StpInterfaceImpl();
    }

}